package net.bcxuexi.tools;

import net.bcxuexi.exception.MyException;

/**
 * 环型byte缓冲区
 */
public class RingByteBuffer {
	// 使用数组存储数据
	byte[] data;
	/**
	 * 环型缓冲区读数据指针
	 */
	private int start;
	/**
	 * 环型缓冲区写读数据指针
	 */
	private int end;

	public RingByteBuffer(int capacity) {
		data = new byte[capacity];
		start = end = 0;
	}

	/**
	 * 把buffer中从offset开始之后的length数据写入缓存
	 * @param buffer 需要添加的数组
	 * @param offset 开始位置
	 * @param length 写入数据长度
	 * @throws MyException
	 * 		如果环型缓冲区没有足够的空闲控件则抛出异常
	 */
	public void put(byte[] buffer,int offset,int length) throws MyException{
		if (end+1 == start
				|| (start == end && start == 0 && length >= data.length)) {
			throw new MyException("空间不够");
		} else if (start < end && length >= data.length - end + start) {
			throw new MyException("空间不够");
		} else if (start > end && length >= start - end) {
			throw new MyException("空间不够");
		} else if (start < end && length < data.length - end + start) {
			if (length < data.length - end) {
				System.arraycopy(buffer, 0, data, end, length);
				end = end + length;
			} else {
				System.arraycopy(buffer, 0, data, end, length - end);
				System.arraycopy(buffer, length - (data.length - end), data, 0,
						length - (data.length - end));
				end = length - (data.length - end);
			}
		} else if (start > end && length < start - end) {
			System.arraycopy(buffer, 0, data, end, length);
			end = end + length;
		} else if (start == end && start == 0 && length < data.length) {
			start = 0;
			System.arraycopy(buffer, 0, data, start, length);
			end = length;
		}
	}
	/**
	 * 从start取leng长度的数据，start标记会跟随变动
	 * @param len
	 * @return
	 */
	public byte[] getS(int len) throws MyException{  
        byte[] arr = new byte[len];  
        if(start<end){  
            if(len<=end-start){  
                System.arraycopy(data, start, arr, 0, len);  
                start=start+len;  
                if(start==end){  
                    start=end=0;  
                }  
                return arr;  
            }else{  
            	throw new MyException("内容不够，无法提取！");
            }  
        }else if(start>end){  
            if(len<=data.length-start){  
                System.arraycopy(data, start, arr, 0, len);  
                start=start+len;  
                if(start==end){  
                    start=end=0;  
                }  
                return arr;               
            }else if(len<=data.length-start+end){  
                System.arraycopy(data, start, arr, 0, data.length-start);  
                System.arraycopy(data, 0, arr, data.length-start,len-(data.length-start));  
                start=len-(data.length-start);  
                if(start==end){  
                    start=end=0;  
                }  
                return arr;               
            }else{  
            	throw new MyException("内容不够，无法提取！");
            }  
        }  
        throw new MyException("内容不够，无法提取！");
    }  
	/**
	 * 从start取leng长度的数据，start标记不会跟随变动
	 * @param len
	 * @return
	 */
	public byte[] get(int len) throws MyException{  
        byte[] arr = new byte[len];  
        if(start<end){  
            if(len<=end-start){  
                System.arraycopy(data, start, arr, 0, len);  
                return arr;  
            }else{  
            	throw new MyException("内容不够，无法提取！");
            }  
        }else if(start>end){  
            if(len<=data.length-start){  
                System.arraycopy(data, start, arr, 0, len);  
                return arr;               
            }else if(len<=data.length-start+end){  
                System.arraycopy(data, start, arr, 0, data.length-start);  
                System.arraycopy(data, 0, arr, data.length-start,len-(data.length-start)); 
                return arr;               
            }else{  
            	throw new MyException("内容不够，无法提取！");
            }  
        }  
        throw new MyException("内容不够，无法提取！");
    } 
	/**
	 * 设置start位置。
	 * @param position start位置
	 */
	public void start(int position){
		if(position>=data.length){
			return;
		}
		start = position;
	}
	/**
	 * 返回start位置
	 * @return
	 */
	public int start(){
		return start;
	}
	/**
	 * 设置end位置。
	 * @param position end位置
	 */
	public void end(int position){
		if(position>=data.length){
			return;
		}
		end = position;
	}
	/**
	 * 返回end位置
	 */
	public int end(){
		return end;
	}
	/**
	 * 缓冲区有效数据大小。
	 * @return
	 */
	public int size(){
		int total=0;
		if(start<end){  
			total = end-start;
		}else if(start>end){
			total = data.length-start+end;
		}
		return total;
	}
	/**
	 * 缓冲区大小
	 */
	public int capacity(){
		return data.length;
	}
	
	/**
	 * 取sb开头，直到eb结尾中间所有的数据.会移动start
	 * 如果start不是已sb开头，则删除数据直到sb开头.
	 * 如果找不到eb结尾的数据则返回null
	 * @param sb
	 * @param eb
	 * @return
	 * @throws MyException 
	 */
	public byte[] getS(byte[] sb,byte[] eb) throws MyException{
		//是否已sb开头
		boolean sbStart = true;
		if(sb.length>size()){
			return null;
		}
		int pos = start;
		for(int i=0;i<sb.length;i++){
			if(pos>=data.length){
				pos = 0;
			}
			if(data[pos]!=sb[i]){
				sbStart = false;
				break;
			}
			pos++;
		}
		if(!sbStart){//需要删除数据 直到sb开头
			MyLog.info("开头数据有问题，删除数据.");
			pos = start;
			while(pos!=end){
				if(pos>=data.length){
					pos = 0;
				}
				int poss = pos;
				boolean hasFindSb=true;
				for(int i=0;i<sb.length;i++){
					if(poss>=data.length){
						poss = 0;
					}
					if(data[poss]!=sb[i]){
						hasFindSb = false;
						break;
					}
					poss++;
				}
				if(hasFindSb){//找到sb数据
					start = pos;
					break;
				}
				pos++;
			}
			if(pos==end){
				start = end =0;
				return null;
			}
		}
		//从start取至eb结束的数据
		if(eb.length>size()){
			return null;
		}
		pos = start;
		int length = 0;
		while(pos!=end){
			if(pos>=data.length){
				pos = 0;
			}
			int poss = pos;
			boolean hasFindEb=true;
			for(int i=0;i<eb.length;i++){
				if(poss>=data.length){
					poss = 0;
				}
				if(data[poss]!=eb[i]){
					hasFindEb = false;
					break;
				}
				poss++;
			}
			if(hasFindEb){//找到eb数据 取数据
				length = length + eb.length;
				byte[] buffer = getS(length);
				return buffer;
			}
			pos++;
			length++;
		}
		return null;
	}
}
